﻿namespace Microsoft.SharePoint.Client
{
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Linq.Expressions;
    using System.Xml;

    public sealed class ConditionalScope : IFromJson
    {
        private bool m_allowAllActions;
        private ClientRuntimeContext m_context;
        private ExecutionScope m_falseScope;
        private ExecutionScope m_scope;
        private Expression<Func<bool>> m_test;
        private bool? m_testResult;
        private ChunkStringBuilder m_testSb;
        private SerializationContext m_testSerializationContext;
        private ExecutionScope m_trueScope;

        public ConditionalScope(ClientRuntimeContext context, Expression<Func<bool>> condition) : this(context, condition, false)
        {
        }

        public ConditionalScope(ClientRuntimeContext context, Expression<Func<bool>> condition, bool allowAllActions)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }
            if (condition == null)
            {
                throw new ArgumentNullException("condition");
            }
            this.m_context = context;
            this.m_test = condition;
            this.m_allowAllActions = allowAllActions;
        }

        internal static Exception CreateInvalidUsageException()
        {
            return new ClientRequestException(Resources.GetString("InvalidUsageOfConditionalScope"));
        }

        bool IFromJson.CustomFromJson(JsonReader reader)
        {
            return false;
        }

        void IFromJson.FromJson(JsonReader reader)
        {
            object obj3;
            Dictionary<string, object> dictionary = reader.ReadObject() as Dictionary<string, object>;
            if (dictionary == null)
            {
                throw new ClientRequestException(Resources.GetString("UnknownResponseData"));
            }
            if (dictionary.TryGetValue("Test", out obj3))
            {
                this.m_testResult = new bool?((bool) obj3);
            }
        }

        private void OnScopeDisposing()
        {
            if ((this.m_trueScope != null) && !this.m_trueScope.Disposed)
            {
                throw CreateInvalidUsageException();
            }
            if ((this.m_falseScope != null) && !this.m_falseScope.Disposed)
            {
                throw CreateInvalidUsageException();
            }
            if ((this.m_trueScope != null) || (this.m_falseScope != null))
            {
                ClientAction lastAction = this.m_context.PendingRequest.LastAction;
                if ((lastAction == null) || !(lastAction is ClientActionExecutionScopeEnd))
                {
                    throw CreateInvalidUsageException();
                }
                if ((((ClientActionExecutionScopeEnd) lastAction).Scope.Name != "IfTrueScope") && (((ClientActionExecutionScopeEnd) lastAction).Scope.Name != "IfFalseScope"))
                {
                    throw CreateInvalidUsageException();
                }
            }
            if (!this.m_allowAllActions)
            {
                for (int i = this.m_context.PendingRequest.Actions.Count - 1; i >= 0; i--)
                {
                    ClientAction objA = this.m_context.PendingRequest.Actions[i];
                    if (object.ReferenceEquals(objA, this.m_scope.ClientActionExecutionScopeStart))
                    {
                        return;
                    }
                    bool flag = false;
                    if (((objA is ClientQueryInternal) || (objA is ClientActionExecutionScopeStart)) || ((objA is ClientActionExecutionScopeEnd) || (objA is ObjectIdentityQuery)))
                    {
                        flag = true;
                    }
                    if (!flag)
                    {
                        ClientActionInstantiateObjectPath path = objA as ClientActionInstantiateObjectPath;
                        if ((path != null) && (((path.Path is ObjectPathConstructor) || (path.Path is ObjectPathIdentity)) || ((path.Path is ObjectPathProperty) || (path.Path is ObjectPathStaticProperty))))
                        {
                            flag = true;
                        }
                    }
                    if (!flag)
                    {
                        throw new ClientRequestException(Resources.GetString("InvalidUsageOfConditionalScopeNowAllowedAction"));
                    }
                }
            }
        }

        public IDisposable StartIfFalse()
        {
            if (((this.m_scope == null) || this.m_scope.Disposed) || (this.m_falseScope != null))
            {
                throw CreateInvalidUsageException();
            }
            ClientAction lastAction = this.m_context.PendingRequest.LastAction;
            if (lastAction == null)
            {
                throw CreateInvalidUsageException();
            }
            if ((!(lastAction is ClientActionExecutionScopeStart) || (((ClientActionExecutionScopeStart) lastAction).Scope.Name != "ConditionalScope")) && (!(lastAction is ClientActionExecutionScopeEnd) || !(((ClientActionExecutionScopeEnd) lastAction).Scope.Name == "IfTrueScope")))
            {
                throw CreateInvalidUsageException();
            }
            this.m_falseScope = new ExecutionScope(this.m_context, "IfFalseScope", null);
            return this.m_falseScope;
        }

        public IDisposable StartIfTrue()
        {
            if (((this.m_scope == null) || this.m_scope.Disposed) || (this.m_trueScope != null))
            {
                throw CreateInvalidUsageException();
            }
            ClientAction lastAction = this.m_context.PendingRequest.LastAction;
            if (lastAction == null)
            {
                throw CreateInvalidUsageException();
            }
            if ((!(lastAction is ClientActionExecutionScopeStart) || (((ClientActionExecutionScopeStart) lastAction).Scope.Name != "ConditionalScope")) && (!(lastAction is ClientActionExecutionScopeEnd) || !(((ClientActionExecutionScopeEnd) lastAction).Scope.Name == "IfFalseScope")))
            {
                throw CreateInvalidUsageException();
            }
            this.m_trueScope = new ExecutionScope(this.m_context, "IfTrueScope", null);
            return this.m_trueScope;
        }

        public IDisposable StartScope()
        {
            if (this.m_scope != null)
            {
                throw CreateInvalidUsageException();
            }
            if (this.m_test == null)
            {
                throw CreateInvalidUsageException();
            }
            this.m_testSb = new ChunkStringBuilder();
            this.m_testSerializationContext = new SerializationContext();
            XmlWriter writer = this.m_testSb.CreateXmlWriter();
            writer.WriteStartElement("Test");
            writer.WriteStartElement("Body");
            new ConditionalExpressionToXmlConverter(this.m_test.Body, writer, null, this.m_testSerializationContext).Convert();
            writer.WriteEndElement();
            writer.WriteEndElement();
            writer.Flush();
            writer.Close();
            this.m_test = null;
            this.m_scope = new ConditionalExecutionScope(this.m_context, this, new ExecutionScopeDisposingCallback(this.OnScopeDisposing));
            this.m_context.AddQueryIdAndResultObject(this.m_scope.Id, this);
            return this.m_scope;
        }

        public bool? TestResult
        {
            get
            {
                return this.m_testResult;
            }
        }

        private class ConditionalExecutionScope : ExecutionScope
        {
            private ConditionalScope m_scope;

            internal ConditionalExecutionScope(ClientRuntimeContext context, ConditionalScope scope, ExecutionScopeDisposingCallback disposingCallback) : base(context, "ConditionalScope", disposingCallback)
            {
                if (scope == null)
                {
                    throw new ArgumentNullException("scope");
                }
                this.m_scope = scope;
            }

            internal override void WriteEnd(XmlWriter writer, SerializationContext serializationContext)
            {
                if ((this.m_scope.m_trueScope == null) && (this.m_scope.m_falseScope == null))
                {
                    writer.WriteEndElement();
                }
                base.WriteEnd(writer, serializationContext);
            }

            internal override void WriteStart(XmlWriter writer, SerializationContext serializationContext)
            {
                base.WriteStart(writer, serializationContext);
                this.m_scope.m_testSb.WriteContentAsRawXml(writer);
                serializationContext.AddObjectPathsFrom(this.m_scope.m_testSerializationContext);
                if ((this.m_scope.m_trueScope == null) && (this.m_scope.m_falseScope == null))
                {
                    writer.WriteStartElement("IfTrueScope");
                    writer.WriteAttributeString("Id", ClientRequest.NextSequenceId.ToString(CultureInfo.InvariantCulture));
                }
            }
        }
    }
}

